package cn.edu.scau.cmi.prewarning.controller;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import javax.persistence.Query;

import org.apache.commons.math3.fitting.PolynomialCurveFitter;
import org.apache.commons.math3.fitting.WeightedObservedPoints;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSONObject;

import cn.edu.scau.cmi.ema.controller.base.CmiEmaController;
import cn.edu.scau.cmi.ema.domain.Address;
import cn.edu.scau.cmi.ema.domain.Event;
import cn.edu.scau.cmi.ema.domain.Foodtype;
import cn.edu.scau.cmi.ema.util.CmiHibernateProxyUtil;
import cn.edu.scau.cmi.ema.util.CurverFitUtil;
import cn.edu.scau.cmi.front.domain.echart.EchartData;
import cn.edu.scau.cmi.front.domain.echart.LineSeries;
import cn.edu.scau.cmi.front.domain.echart.Link;
import cn.edu.scau.cmi.front.domain.echart.Node;
import cn.edu.scau.cmi.front.domain.echart.PieSeries;
import cn.edu.scau.cmi.front.service.CmiFoodTypeIdService;
import cn.edu.scau.cmi.prewarning.domain.Eventsummary;
import cn.edu.scau.cmi.prewarning.domain.Eventsummarydetail;
import cn.edu.scau.cmi.yanghongyu.util.GetChildren;


@RestController
public class EchartPrewarningRestController extends CmiEmaController {

	@Autowired
	CmiFoodTypeIdService cmiFoodTypeIdService;

	/**
	 * 食品类型-事件柱状图使用该接口
	 * 
	 * @param attrMap 同addressBar方法的attrMap
	 * @return
	 */
	@RequestMapping(value = "/front/foodtypeBar", method = RequestMethod.POST)
	public Map<String, Object> foodtypeBar(@RequestBody Map<String, String> attrMap) {

		List<Integer> foodtypeList = new ArrayList<>();
		foodtypeList.add(562);
		foodtypeList.add(565);
		foodtypeList.add(566);
		foodtypeList.add(583);
		foodtypeList.add(591);
		foodtypeList.add(1642);

		List<String> xList = new ArrayList<>();
		List<Integer> yList = new ArrayList<>();
		Integer yMax = 0;

		for (Integer foodtypeId : foodtypeList) {
//			在json数据中添加foodtypeid
			attrMap.put("foodtypeId", String.valueOf(foodtypeId));
			Foodtype foodtype = foodtypeService.findFoodtypeByPrimaryKey(foodtypeId);
			xList.add(foodtype.getName());
//			Integer count = cmiEventDAO.countEventByFoodtypeIdAndMap(foodtypeId, attrMap);
//			Integer count = cmiEventDAO.countEventByMap(attrMap);
			Integer count = cmiEventDAO.countEvent4MapAndBarTmp(attrMap);
			
			
			
			yMax = yMax < count ? count : yMax;
			yList.add(count);
		}

		yMax = (int) (yMax * 1.2);
		Map<String, Object> map = new HashMap<>();
		map.put("x", xList);
		map.put("y", yList);
		map.put("yMax", yMax);
		return map;
	}

	/**
	 * 获取省份地址和对应的事件数 允许根据年份、食品类型等条件进行筛选() EMA中国地图和地址-事件柱状图使用该接口
	 * 
	 * 年份：key=discoveryTime 或 key=sourceTime, value="2000-2020"（包含2000年和2020年） 或
	 * value="2011-2011"（只统计2011年） 食品类型：key=foodtypeid, value为子库的id
	 * 
	 * @param addressType 0为来源地址，1为发现地址
	 * @return
	 */
	@RequestMapping(value = "/front/countEventQuantity4echart", method = RequestMethod.POST)
	public Map<String, Object> countEventQuantity4echart(@RequestBody Map<String, String> eventCondtionMap) {
		
		List<String> provinceNameList = new ArrayList<>();
		List<Integer> provinceEventQuantityList = new ArrayList<>();
		
		Set<Address> provinceSet = addressDAO.findAddresssByParent(9, -1, -1);
		
		List<Address> provinceList = new ArrayList<Address>(provinceSet);
		
		Collections.sort(provinceList);

		Integer maxEventQuantity = 0;
		
		Map<String, Object> provinceEventQuantityMap = new LinkedHashMap<>();
		
		for (Address province : provinceList) {
//			获取省的数量：将省key-value添加到了map中
			String provinceName = province.getName();
			eventCondtionMap.put("province", provinceName);
//			Integer count = cmiEventDAO.countEventByAddressName(addressName, addressTypeStr);
//			Integer count = cmiEventDAO.countEventByAddressNameAndMap(addressName, addressTypeStr, attrMap);

//			查询条件：eventCondtionMap : {addressType=discoveryprovince, foodtypeId=1642, timeType=discoveryTime, starTime=, endTime=}
			Integer eventQuantity = cmiEventDAO.countEvent4MapAndBarTmp(eventCondtionMap);
//			数据库中有省，市等，echart.js不需要，这里去除省、市等字符。
			if (provinceName.endsWith("省") || provinceName.endsWith("市"))
				provinceName = provinceName.substring(0, provinceName.length() - 1);
			else if (provinceName.endsWith("特别行政区"))
				provinceName = provinceName.substring(0, provinceName.length() - 5);
			else if (provinceName.endsWith("自治区")) {
				provinceName = provinceName.substring(0, provinceName.length() - 3);
				if (provinceName.length() > 3)
					provinceName = provinceName.substring(0, 2);
			}
			
			provinceNameList.add(provinceName);
			provinceEventQuantityList.add(eventQuantity);
			
			provinceEventQuantityMap.put(provinceName, eventQuantity);
			
			
			maxEventQuantity = maxEventQuantity < eventQuantity ? eventQuantity : maxEventQuantity;
			System.out.println("---地点：" + provinceName + "，事件数量" + eventQuantity + "，当前最大的事件数量" + maxEventQuantity);
			
		}
//		按照address的id排序
		maxEventQuantity = (int) (maxEventQuantity * 1.2);
		
//		map.put("provinceNameList", provinceNameList);
//		map.put("provinceEventQuantityList", provinceEventQuantityList);
//		provinceEventQuantityMap.put("最多数量", maxEventQuantity);
		return provinceEventQuantityMap;
//		return echartData;
	}

	@RequestMapping(value = "/front/lineEchart/{addressTypeId}/{parentId}/{timeTypeId}", method = RequestMethod.GET)
	public EchartData lineEchart(@PathVariable Integer addressTypeId, @PathVariable Integer parentId,
			@PathVariable Integer timeTypeId) {
		String addressType = addressTypeId == 0 ? "source" : "discovery";
		String timeType = timeTypeId == 0 ? "source" : "discovery";
		String minTime = "2000-01";

//		String parameter = request.getParameter("id");
//		int parentId = parameter == null ? 9 : Integer.valueOf(parameter);

		List<String> legend = new ArrayList<String>();
		List<String> category = new ArrayList<String>();
		List<LineSeries> series = new ArrayList<LineSeries>();

		Set<Address> addressSet = addressDAO.findAddresssByParent(parentId, -1, -1);

		// 填充legend（数据分组）
		for (Address address : addressSet) {
			legend.add(address.getName());
		}

		Set<Integer> addressIdSet = new HashSet<>();
		for (Address address : addressSet) {
			addressIdSet.add(address.getId());
		}

		if (addressIdSet.size() <= 0)
			return null;

		// TODO 根据时间(精确到年份)和地址得到事件数量
		String maxTime = cmiEventDAO.findMaxDiscoveryTimeInEventByDiscoveryAddress(addressIdSet, -1, -1);
		if (minTime == null) {
			minTime = cmiEventDAO.findMinDiscoveryTimeInEventByDiscoveryAddress(addressIdSet, -1, -1);
		}

		if (maxTime == null || minTime == null)
			return null;

		int startYear = Integer.valueOf(minTime.split("-")[0]);
		int startMonth = Integer.valueOf(minTime.split("-")[1]);
		int endYear = Integer.valueOf(maxTime.split("-")[0]);
		int endMonth = Integer.valueOf(maxTime.split("-")[1]);

		// 填充category（横坐标）
		for (int i = startYear; i <= endYear; i++) {
			category.add(String.valueOf(i));
//			int j = i == startYear ? startMonth : 1;
//			for(; j <= 12 && i < endYear || j <= endMonth && i == endYear; j++) {
//				String s = String.format("%d-%02d", i, j);
//				category.add(s);
//			}
		}

		for (Address address : addressSet) {
			ArrayList<Long> data = new ArrayList<Long>();
			for (String time : category) {
				// 已有 address.id 和 time，求count(event)
//				Long count = cmiEventDAO.countEventsByDiscoveryAddressAndDiscoveryTimeAndfoodtypeId(address.getId(),
//						time, foodtypeId, -1, -1);
				Long count = cmiEventDAO.countEventByAddressNameAndTime(address.getName(), addressType, time, timeType);
				data.add(count);
			}
			series.add(new LineSeries(address.getName(), "line", data));
		}

		return new EchartData(legend, category, series);
	}

//	提供接口给预警系统，导出事件到emaprewarning中。
//	从echart获取数据。
//	echart的数据从哪里来的呢？？？
	
	@ResponseBody
	@RequestMapping(value = "/exportEventsummaryOnDiscoveryaddressFromEmaEchart/{addressTypeId}/{addressId}/{timeTypeId}", method = {RequestMethod.POST, RequestMethod.GET})
	public Object exportEventsummaryOnDiscoveryaddressFromEmaEchart() {
//		（1）食物发展趋势
//		（2）食物类型发展趋势
//		（3）来源地址发展趋势
//		（4）发现地址发展趋势
		
//		已有的年份，从2020年开始计算，其他的不管了。
//		int beginYear = 2000; 结束年使用2021年，因为2022年还没有开始。
		int endYear = Calendar.getInstance().get(Calendar.YEAR)-1;
		
		Set<Address> provinces = addressDAO.findAddressById(9).getAddresssForParent();
		
//		当前只能把所有的数据封装为各省每年的数量的多少，其他更详细的地址分类因为数据不足，效果没有。
		
//		地址年份趋势分析
		Set<Eventsummary> eventsummaries = new LinkedHashSet<Eventsummary>();
		int tmpTrendId = 1;
		int tmpTrendetailId = 1;
		for(Address province:provinces) {//ema中的地址
			Eventsummary eventsummary = new Eventsummary();
			cn.edu.scau.cmi.prewarning.domain.Address emaprewarningAdderss  =  new cn.edu.scau.cmi.prewarning.domain.Address();
			
			emaprewarningAdderss.setName(province.getName());
			eventsummary.setDiscoveryaddress(emaprewarningAdderss);//emaprewarning简化了的地址，
			
			eventsummary.setId(tmpTrendId++);
//			tmpTrendId++;
			
			for(int year = 2001; year <= endYear; year++) {
				Foodtype foodtype = null;
				Long eventQuantity = cmiEventDAO.countEcharteventsByDiscoveryaddressAndDiscoverytime(province, year, foodtype );
				Eventsummarydetail eventsummarydetail = new Eventsummarydetail();
				eventsummarydetail.setEventsummary(eventsummary);
				eventsummarydetail.setQuantity(eventQuantity.intValue());
				Calendar.getInstance().set(Calendar.YEAR, year);
				Calendar t = Calendar.getInstance();
				t.set(year, 6, 6);//年进行统计，不管月和日期
				eventsummarydetail.setTime(t );
				eventsummarydetail.setId(tmpTrendetailId++);
				
				eventsummary.getEventsummarydetailsForEventsummary().add(eventsummarydetail);
				
				System.out.println("---" + province.getName() + " " + year + " " + eventQuantity);
			}
			eventsummaries.add(eventsummary);
		}
		String trendsString =  cmiPsonService.toJsonString(eventsummaries, 2);
		return JSONObject.parse(trendsString);
	}
	
	
	@ResponseBody
	@RequestMapping(value = "/exportEventsummaryOnFoodtypeFromEmaEchart", method = {RequestMethod.POST, RequestMethod.GET})
	public Object exportEventsummaryOnFoodtypeFromEmaEchart() {
//		（2）食物类型发展趋势
//		已有的年份，从2020年开始计算，其他的不管了。
//		int beginYear = 2001; 结束年份是上一年。
		int endYear = Calendar.getInstance().get(Calendar.YEAR) -1;
		//Set<Foodtype> mainFoodtype = getMainFoodtype();//561 577 578 1650
		Set<Foodtype> mainFoodtype = new LinkedHashSet<Foodtype>(); 

		Set<Foodtype> mainProduceFoodtype = foodtypeDAO.findFoodtypeById(561).getFoodtypesForParent();
		Set<Foodtype> mainPlantFoodtype = foodtypeDAO.findFoodtypeById(577).getFoodtypesForParent();
		Set<Foodtype> mainAnimalFoodtype = foodtypeDAO.findFoodtypeById(578).getFoodtypesForParent();
		Set<Foodtype> mainAquaticFoodtype = foodtypeDAO.findFoodtypeById(1650).getFoodtypesForParent();
		
		mainFoodtype.addAll(mainProduceFoodtype);
		mainFoodtype.addAll(mainPlantFoodtype);
		mainFoodtype.addAll(mainAnimalFoodtype);
		mainFoodtype.addAll(mainAquaticFoodtype);
		
		Set<Eventsummary> eventsummaries = new LinkedHashSet<Eventsummary>();
		int tmpTrendId = 1;
		int tmpTrendetailId = 1;
		
//		食物类别 -> 年份，每一个食物类别是一个trend，每一个食物类别的年事件是一个trendetail.
		for(Foodtype foodtype : mainFoodtype) {
			Eventsummary eventsummary = new Eventsummary();
			eventsummary.setId(tmpTrendId++);//这个id是一个瞬态的id，如果没有的化，在集合中添加不了，因为这个是主键。
			cn.edu.scau.cmi.prewarning.domain.Foodtype emaprewarningFoodtype  =  new cn.edu.scau.cmi.prewarning.domain.Foodtype();
//			需要把foodtype保存到emaprewarning中。
			emaprewarningFoodtype.setName(foodtype.getName());
			eventsummary.setfoodtype(emaprewarningFoodtype);
			for(int year = 2001; year <= endYear; year ++) {
				Long eventQuantity = cmiEventDAO.countEcharteventsByFoodtypeAndDiscoverytime(foodtype, year);//按照年度计算
				
				Eventsummarydetail eventsummarydetail = new Eventsummarydetail();
				eventsummarydetail.setEventsummary(eventsummary);
				eventsummarydetail.setQuantity(eventQuantity.intValue());
				Calendar.getInstance().set(Calendar.YEAR, year);
				Calendar t = Calendar.getInstance();
				t.set(year, 6, 6);//年进行统计，不管月和日期
				eventsummarydetail.setTime(t );
				eventsummarydetail.setId(tmpTrendetailId++);
				
				eventsummary.getEventsummarydetailsForEventsummary().add(eventsummarydetail);
				
				System.out.println("---" + emaprewarningFoodtype.getName() + " " + year + " " + eventQuantity);
			}
			
			eventsummaries.add(eventsummary);
			
		}
		String trendsString =  cmiPsonService.toJsonString(eventsummaries, 2);
		return JSONObject.parse(trendsString);
	}
	
	
	@RequestMapping(value = "/front/lineAddressWithPrediction/{addressTypeId}/{addressId}/{timeTypeId}", method = RequestMethod.POST)
	public EchartData lineAddressWithPrediction(@PathVariable Integer addressTypeId, @PathVariable Integer addressId,
			@PathVariable Integer timeTypeId, @RequestBody Map<String, String> attrMap) {
		String addressType = addressTypeId == 0 ? "source" : "discovery";
		String timeType = timeTypeId == 0 ? "source" : "discovery";
		String minTime = "2000";
		Calendar cal = Calendar.getInstance();
//		String maxTime = String.valueOf(cal.get(Calendar.YEAR) - 1);
		String maxTime = String.valueOf(cal.get(Calendar.YEAR) + 1);

		List<String> legendDates = new ArrayList<String>();//图标
		List<String> category = new ArrayList<String>();//xAxis.
		List<LineSeries> series = new ArrayList<LineSeries>();

		Set<Address> addressSet = null;
		if (addressId != 0) {
			addressSet = new HashSet<>();
			addressSet.add(addressService.findAddressByPrimaryKey(addressId));
		} else {
			addressSet = addressDAO.findAddresssByParent(9, -1, -1);
		}

		// 填充category（横坐标）
		for (int i = Integer.parseInt(minTime); i < Integer.parseInt(maxTime); i++) {
			category.add(String.valueOf(i));
		}

		for (Address address : addressSet) {
			// 填充legend（数据分组）
			legendDates.add(address.getName());

			ArrayList<Long> datas = new ArrayList<Long>();
			for (String time : category) {
				Long count = cmiEventDAO.countEventByAddressNameAndTime(address.getName(), addressType, time, timeType, attrMap);
				datas.add(count);
			}

			// category加上maxTime，data加上预测值
			datas.add(CurverFitUtil.predictNextByPolynomialCurveFitter(strList2LongList(category), datas));
			series.add(new LineSeries(address.getName(), "line", datas));

		}

		category.add(maxTime);
		return new EchartData(legendDates, category, series);
	}

	@RequestMapping(value = "/front/lineFoodtypeWithPrediction/{foodtypeId}/{timeTypeId}", method = RequestMethod.POST)
	public EchartData lineFoodtypeWithPrediction(@PathVariable Integer foodtypeId, @PathVariable Integer timeTypeId,
			@RequestBody Map<String, String> attrMap) {
		String timeType = timeTypeId == 0 ? "source" : "discovery";
		String minTime = "2000";
		Calendar cal = Calendar.getInstance();
		String maxTime = String.valueOf(cal.get(Calendar.YEAR) - 1);

		List<String> legend = new ArrayList<String>();
		List<String> category = new ArrayList<String>();
		List<LineSeries> series = new ArrayList<LineSeries>();

		Set<Integer> foodtypeSet = new HashSet<>();
		if (foodtypeId == 0) {
			foodtypeSet.add(1642);
			foodtypeSet.add(565);
			foodtypeSet.add(583);
			foodtypeSet.add(562);
			foodtypeSet.add(566);
		} else {
			foodtypeSet.add(foodtypeId);
		}
		// 填充category（横坐标）
		for (int i = Integer.parseInt(minTime); i < Integer.parseInt(maxTime); i++) {
			category.add(String.valueOf(i));
		}

		for (Integer i : foodtypeSet) {
			Foodtype foodtype = foodtypeService.findFoodtypeByPrimaryKey(i);

			// 填充legend（数据分组）
			legend.add(foodtype.getName());

			ArrayList<Long> data = new ArrayList<Long>();
			for (String time : category) {
				Long count = cmiEventDAO.countEventByFoodtypeId(i, time, timeType, attrMap);
				data.add(count);
			}

			data.add(CurverFitUtil.predictNextByPolynomialCurveFitter(strList2LongList(category), data));

			series.add(new LineSeries(foodtype.getName(), "line", data));

		}

		category.add(maxTime);
		return new EchartData(legend, category, series);
	}

	private List<Long> strList2LongList(List<String> list) {
		List<Long> l = new ArrayList<>();
		for (String s : list) {
			l.add(Long.parseLong(s));
		}
		return l;
	}


	private Set<Integer> getFoodtypeIdSet(Integer foodtypeId) {
		if (cmiFoodTypeIdService.isAgriculturalProduct(foodtypeId)) {
			return cmiFoodTypeIdService.getAgriculturalProductIdSet();
		} else if (cmiFoodTypeIdService.isAquatic(foodtypeId)) {
			return cmiFoodTypeIdService.getAquaticIdSet();
		} else if (cmiFoodTypeIdService.isGrainAndOil(foodtypeId)) {
			return cmiFoodTypeIdService.getGrainAndOilIdSet();
		} else if (cmiFoodTypeIdService.isMeat(foodtypeId)) {
			return cmiFoodTypeIdService.getMeatIdSet();
		} else if (cmiFoodTypeIdService.isMilk(foodtypeId)) {
			return cmiFoodTypeIdService.getMilkIdSet();
		} else if (cmiFoodTypeIdService.isOther(foodtypeId)) {
			return cmiFoodTypeIdService.getOtherIdSet();
		}
		return null;
	}

	@RequestMapping(value = "/front/lineWithFoodtypeEchart/{parentId}", method = RequestMethod.GET)
	public EchartData lineWithFoodtypeEchart(@PathVariable Integer parentId) {
		List<String> legend = new ArrayList<String>(); // 线的种类
		List<String> category = new ArrayList<String>(); // 横坐标
		List<LineSeries> series = new ArrayList<LineSeries>(); // 纵坐标

		Set<Address> addressSet = addressDAO.findAddresssByParent(parentId, -1, -1);

		Set<Integer> foodtypesId = new HashSet<>();
		foodtypesId.add(562);
		foodtypesId.add(565);
		foodtypesId.add(566);
		foodtypesId.add(583);
		foodtypesId.add(592);
		foodtypesId.add(1642);
		Set<Foodtype> foodtypeSet = foodtypeService.loadFoodtypesByIdSet(foodtypesId);

		// 填充legend（数据分组）
		for (Foodtype foodtype : foodtypeSet) {
			legend.add(foodtype.getName());
		}

		// 填充category（横坐标）
		for (Address address : addressSet) {
			category.add(address.getName());
		}

		for (Foodtype foodtype : foodtypeSet) {
			ArrayList<Long> data = new ArrayList<Long>();
			Set<Integer> foodtypeIdSet = getFoodtypeIdSet(foodtype.getId());
			for (Address address : addressSet) {
				// 已有 address.id 和 time，求count(event)
				Long count = cmiEventDAO.countEventsByDiscoveryAddressAndfoodtypeIds(address.getId(), foodtypeIdSet, -1,
						-1);
				data.add(count);
			}
			series.add(new LineSeries(foodtype.getName(), "line", data));
		}

		return new EchartData(legend, category, series);
//		return null;
	}

	@RequestMapping(value = "/front/pieEchart/{parentId}/{foodtypeId}", method = RequestMethod.GET)
	public List<PieSeries> pieEchart(@PathVariable Integer parentId, @PathVariable Integer foodtypeId) {
		Set foodtypeIdSet = null;
		if (cmiFoodTypeIdService.isAgriculturalProduct(foodtypeId)) {
			foodtypeIdSet = cmiFoodTypeIdService.getAgriculturalProductIdSet();
		} else if (cmiFoodTypeIdService.isAquatic(foodtypeId)) {
			foodtypeIdSet = cmiFoodTypeIdService.getAquaticIdSet();
		} else if (cmiFoodTypeIdService.isGrainAndOil(foodtypeId)) {
			foodtypeIdSet = cmiFoodTypeIdService.getGrainAndOilIdSet();
		} else if (cmiFoodTypeIdService.isMeat(foodtypeId)) {
			foodtypeIdSet = cmiFoodTypeIdService.getAgriculturalProductIdSet();
		} else if (cmiFoodTypeIdService.isMilk(foodtypeId)) {
			foodtypeIdSet = cmiFoodTypeIdService.getMilkIdSet();
		} else if (cmiFoodTypeIdService.isOther(foodtypeId)) {
			foodtypeIdSet = cmiFoodTypeIdService.getOtherIdSet();
		}

		List<PieSeries> series = new ArrayList<PieSeries>();

		Set<Address> addressSet = addressDAO.findAddresssByParent(parentId, -1, -1);

		for (Address address : addressSet) {
			// 已有 address.id 和 time，求count(event)
			Long count = cmiEventDAO.countEventsByDiscoveryAddressAndDiscoveryTimeAndfoodtypeIds(address.getId(), "",
					foodtypeIdSet, -1, -1);
			if (count > 0)
				series.add(new PieSeries(address.getName(), count));
		}

		series.sort(new Comparator<PieSeries>() {
			@Override
			public int compare(PieSeries o1, PieSeries o2) {
				return (int) (o1.getValue() - o2.getValue());
			}
		});

		return series;
//		return null;
	}

	@RequestMapping(value = "/front/graphEchart/{eventId}", method = RequestMethod.GET)
	public Map<String, Object> graphEchart(@PathVariable Integer eventId) {
		ArrayList<Node> nodes = new ArrayList<Node>();
		ArrayList<Link> links = new ArrayList<Link>();

		Event event = eventService.findEventByPrimaryKey(eventId);
		nodes.add(new Node(0, event.getClass().getSimpleName() + "_" + event.getId(), event.getName(), 10, 10));
//		nodes.add(new Node(0, event.getClass().getSimpleName() + "-" + event.getId() + 1, event.getName(), 10, 10));
//		links.add(new Link(event.getClass().getSimpleName() + "-" + event.getId() + "-" + event.getClass().getSimpleName() + "-" + event.getId() + 1, event.getClass().getSimpleName() + "-" + event.getId(), event.getClass().getSimpleName() + "-" + event.getId() + 1));

		Map<String, Object> graph = new HashMap<String, Object>();
		graph.put("nodes", nodes);
		graph.put("links", links);
		return graph;
	}

	@RequestMapping(value = "/front/graphEchart/getNextGraph/{name}", method = RequestMethod.GET)
	public Map<String, Object> getNextGraph(@PathVariable String name)
			throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException,
			IllegalArgumentException, InvocationTargetException {
		ArrayList<Node> nodes = new ArrayList<Node>();
		ArrayList<Link> links = new ArrayList<Link>();

		System.out.println(name);
		String className = name.split("_")[0];
		int classId = Integer.valueOf((name.split("_")[1]));

		Class<?> classService = Class.forName("cn.edu.scau.cmi.ema.service." + className + "Service");
		Object bean = (new GetChildren()).getApplicationContext().getBean(className + "Service", classService);
		Method findObjectByPrimaryKey = classService.getMethod("find" + className + "ByPrimaryKey", Integer.class);

		Object object = findObjectByPrimaryKey.invoke(bean, classId);
		Field[] fields = object.getClass().getDeclaredFields();
		Field.setAccessible(fields, true);
		for (Field field : fields) {
			String fieldName = field.getName();
			Object fieldValue = null;
			try {
				fieldValue = field.get(object);
				fieldValue = CmiHibernateProxyUtil.deproxy(fieldValue);
				if (fieldValue == null)
					continue;
				if (fieldValue instanceof Collection<?> && ((Collection<?>) fieldValue).size() <= 0)
					continue;
				if (!(fieldValue instanceof Collection<?>)
						&& !fieldValue.getClass().getName().startsWith("cn.edu.scau.cmi.ema.domain"))
					continue;

				if (!(fieldValue instanceof Collection<?>)) {
					String nodeId = fieldValue.getClass().getSimpleName() + "_" + getValue(fieldValue, "id");
					String linkId = name + "_" + nodeId;
					nodes.add(new Node(0, nodeId, getValue(fieldValue, "name"), 10, 10));
					links.add(new Link(linkId, name, nodeId));
				} else {
					for (Object o : (Collection<?>) fieldValue) {
						String nodeId = o.getClass().getSimpleName() + "_" + getValue(o, "id");
						String linkId = nodeId + "_" + name;
						nodes.add(new Node(0, nodeId, getValue(o, "name"), 10, 10));
						links.add(new Link(linkId, nodeId, name));
					}
				}
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		Map<String, Object> graph = new HashMap<String, Object>();
		graph.put("nodes", nodes);
		graph.put("links", links);
		return graph;
	}

	private String getValue(Object obj, String name) throws IllegalArgumentException, IllegalAccessException {
		Field[] fields = obj.getClass().getDeclaredFields();
		Field.setAccessible(fields, true);
		for (Field field : fields) {
			String fieldName = field.getName();
			if (name.equals(fieldName)) {
				return String.valueOf(field.get(obj));
			}
		}
		return null;
	}
}
